fix(deps): update dependency re2 to v1.26.1 [security] - #17855
Open
renovate[bot] wants to merge 1 commit into
Open
fix(deps): update dependency re2 to v1.26.1 [security]#17855renovate[bot] wants to merge 1 commit into
renovate[bot] wants to merge 1 commit into
Conversation
Contributor
|
このPRによるapi.jsonの差分 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #17855 +/- ##
============================================
+ Coverage 13.99% 26.13% +12.14%
============================================
Files 248 1175 +927
Lines 12041 40114 +28073
Branches 4036 11118 +7082
============================================
+ Hits 1685 10485 +8800
- Misses 8118 23779 +15661
- Partials 2238 5850 +3612 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Contributor
🖥 Frontend Diagnostics Report(No significant changes) Requests by resource type
V8 heap snapshot statistics
📦 Bundle StatsChunk size diff (0 updated, 0 added, 0 removed)
Startup chunk size (0 updated, 0 added, 0 removed)
Startup chunks are the Vite entry for
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Contributor
⚙️ Backend Diagnostics ReportMemory: After GC(No significant changes) V8 Heap Snapshot Statistics
|
renovate
Bot
force-pushed
the
renovate/npm-re2-vulnerability
branch
from
August 12, 2026 02:58
6ec7ef8 to
a32c42c
Compare
renovate
Bot
force-pushed
the
renovate/npm-re2-vulnerability
branch
from
August 14, 2026 21:49
a32c42c to
dee467a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
1.26.0→1.26.1node-re2: Out-of-bounds heap read in
replace/splitvia aBufferending in a truncated multi-byte UTF-8 character → adjacent heap memory disclosed to JavaScriptCVE-2026-71498 / GHSA-j4r3-hg7j-8chg
More information
Details
Summary
re2infers a character's byte length from its UTF-8 lead byte alone, with no bound on thebytes actually remaining in the input.
Bufferarguments reach the native layer verbatim —only strings are re-encoded into well-formed UTF-8 — so a
Bufferwhose last byte is amulti-byte lead promises continuation bytes that are not there, and the result builders read
up to 3 bytes past the end of the buffer. In
replace()andsplit()those bytes are copiedinto the returned
Buffer, disclosing adjacent heap memory to JavaScript. The trigger isdeterministic and requires no special heap grooming.
Only
Bufferinput is affected. String input was never at risk: re-encoding guarantees everymulti-byte sequence is complete.
Root cause
getUtf8CharSizemaps a lead byte to a length of 1–4 and never sees the input size:Callers then read that many bytes. In the zero-width branch of
replace(), the guard provesonly that at least one byte remains:
offset < sizepermitsoffset == size - 1, so a lead byte of0xF0makesappendreaddata[size],data[size + 1]anddata[size + 2].Seven read sites shared the defect:
lib/replace.cc(zero-width branch)lib/replace.cc(callback replacer)lib/replace.cc(replacement scan)lib/split.cclib/pattern.cctranslateRegExp(x2)lib/pattern.ccescapeRegExpThree further callers were not vulnerable, because they use the result only to advance an
index and never dereference past the end:
getUtf16PositionByCounterinlib/wrapped_re2.h(clamps its return to the buffer size),
lib/match.cc(the value feedsRE2::Match, whichrejects
startpos > endpos), and thegetMaxSubmatchscan inlib/replace.cc(an overshootjust ends the loop).
Proof of concept
Each call returns more bytes than were supplied; the trailing bytes are heap contents and vary
between runs.
0xC2(2-byte lead) and0xE2(3-byte lead) over-read 1 and 2 bytes respectively;0xF0over-reads 3.
For the pattern path the over-read occurs in
translateRegExp/escapeRegExp, which runbefore RE2 validates the pattern, but RE2 then rejects the malformed input, so the bytes are
discarded rather than returned:
Impact
Information disclosure (
replace,split). Up to 3 bytes of heap memory adjacent to theinput buffer are returned to JavaScript per call. The read is repeatable, so an attacker who
controls
Bufferinput and observes output can sample heap memory incrementally. What landsthere depends on allocator layout and is not directly steerable, but it may include fragments
of other buffers.
Out-of-bounds read (pattern compilation). No disclosure path, since the malformed pattern
is rejected — but the read is still undefined behavior and can fault if the buffer ends on a
page boundary.
Applications that pass only strings, or only well-formed UTF-8 buffers, are unaffected. The
exposure matters most where
re2is used as intended: running patterns or subjects derivedfrom untrusted input.
Suggested fix
Clamp the inferred character size to the bytes that actually remain, at every site whose result
indexes the buffer:
This is O(1) and changes no algorithm's complexity. A truncated tail then round-trips as the
bytes it really holds, which preserves the documented contract that
Bufferinput is passedthrough verbatim. Rejecting malformed UTF-8 in
Bufferinput would also close the hole, butis a breaking API change.
Resolution
Fixed in
re2@1.26.1.All seven read sites now clamp the character size to the remaining input, so a
Bufferendingin a truncated multi-byte character round-trips as its own bytes instead of reading past the
end. Regression tests cover the subject, replacement and pattern positions for 2-, 3- and
4-byte leads, including partially truncated sequences.
Remediation: upgrade to
re2@1.26.1or later.Workaround (if you cannot upgrade): pass strings rather than
Buffers, or validate thatBufferinput is well-formed UTF-8 before callingreplace,split, or theRE2constructor — for example
Buffer.compare(Buffer.from(buf.toString('utf8')), buf) === 0.Reported by @OvOhao in #272.
Severity
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:LReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
node-re2: Out-of-bounds heap read in
replace/splitvia aBufferending in a truncated multi-byte UTF-8 character → adjacent heap memory disclosed to JavaScriptCVE-2026-71498 / GHSA-j4r3-hg7j-8chg
More information
Details
Summary
re2infers a character's byte length from its UTF-8 lead byte alone, with no bound on thebytes actually remaining in the input.
Bufferarguments reach the native layer verbatim —only strings are re-encoded into well-formed UTF-8 — so a
Bufferwhose last byte is amulti-byte lead promises continuation bytes that are not there, and the result builders read
up to 3 bytes past the end of the buffer. In
replace()andsplit()those bytes are copiedinto the returned
Buffer, disclosing adjacent heap memory to JavaScript. The trigger isdeterministic and requires no special heap grooming.
Only
Bufferinput is affected. String input was never at risk: re-encoding guarantees everymulti-byte sequence is complete.
Root cause
getUtf8CharSizemaps a lead byte to a length of 1–4 and never sees the input size:Callers then read that many bytes. In the zero-width branch of
replace(), the guard provesonly that at least one byte remains:
offset < sizepermitsoffset == size - 1, so a lead byte of0xF0makesappendreaddata[size],data[size + 1]anddata[size + 2].Seven read sites shared the defect:
lib/replace.cc(zero-width branch)lib/replace.cc(callback replacer)lib/replace.cc(replacement scan)lib/split.cclib/pattern.cctranslateRegExp(x2)lib/pattern.ccescapeRegExpThree further callers were not vulnerable, because they use the result only to advance an
index and never dereference past the end:
getUtf16PositionByCounterinlib/wrapped_re2.h(clamps its return to the buffer size),
lib/match.cc(the value feedsRE2::Match, whichrejects
startpos > endpos), and thegetMaxSubmatchscan inlib/replace.cc(an overshootjust ends the loop).
Proof of concept
Each call returns more bytes than were supplied; the trailing bytes are heap contents and vary
between runs.
0xC2(2-byte lead) and0xE2(3-byte lead) over-read 1 and 2 bytes respectively;0xF0over-reads 3.
For the pattern path the over-read occurs in
translateRegExp/escapeRegExp, which runbefore RE2 validates the pattern, but RE2 then rejects the malformed input, so the bytes are
discarded rather than returned:
Impact
Information disclosure (
replace,split). Up to 3 bytes of heap memory adjacent to theinput buffer are returned to JavaScript per call. The read is repeatable, so an attacker who
controls
Bufferinput and observes output can sample heap memory incrementally. What landsthere depends on allocator layout and is not directly steerable, but it may include fragments
of other buffers.
Out-of-bounds read (pattern compilation). No disclosure path, since the malformed pattern
is rejected — but the read is still undefined behavior and can fault if the buffer ends on a
page boundary.
Applications that pass only strings, or only well-formed UTF-8 buffers, are unaffected. The
exposure matters most where
re2is used as intended: running patterns or subjects derivedfrom untrusted input.
Suggested fix
Clamp the inferred character size to the bytes that actually remain, at every site whose result
indexes the buffer:
This is O(1) and changes no algorithm's complexity. A truncated tail then round-trips as the
bytes it really holds, which preserves the documented contract that
Bufferinput is passedthrough verbatim. Rejecting malformed UTF-8 in
Bufferinput would also close the hole, butis a breaking API change.
Resolution
Fixed in
re2@1.26.1.All seven read sites now clamp the character size to the remaining input, so a
Bufferendingin a truncated multi-byte character round-trips as its own bytes instead of reading past the
end. Regression tests cover the subject, replacement and pattern positions for 2-, 3- and
4-byte leads, including partially truncated sequences.
Remediation: upgrade to
re2@1.26.1or later.Workaround (if you cannot upgrade): pass strings rather than
Buffers, or validate thatBufferinput is well-formed UTF-8 before callingreplace,split, or theRE2constructor — for example
Buffer.compare(Buffer.from(buf.toString('utf8')), buf) === 0.Reported by @OvOhao in #272.
Severity
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:LReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Release Notes
uhop/node-re2 (re2)
v1.26.1Compare Source
Configuration
📅 Schedule: (in timezone Asia/Tokyo)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.